package handling.mina;

import client.MapleClient;
import constants.ServerConstants;
import handling.SendPacketOpcode;
import java.io.PrintStream;
import java.util.concurrent.locks.Lock;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolEncoder;
import org.apache.mina.filter.codec.ProtocolEncoderOutput;
import server.ServerProperties;
import tools.FileoutputUtil;
import tools.HexTool;
import tools.MapleAESOFB;
import tools.StringUtil;
import tools.data.input.ByteArrayByteStream;
import tools.data.input.GenericLittleEndianAccessor;

public class MaplePacketEncoder implements ProtocolEncoder {

    @Override
    public void encode(IoSession session, Object message, ProtocolEncoderOutput out) throws Exception {
        MapleClient client = (MapleClient) session.getAttribute(MapleClient.CLIENT_KEY);

        if (client != null) {
            MapleAESOFB send_crypto = client.getSendCrypto();
            byte[] input = (byte[]) (byte[]) message;
            
            //if ((ServerProperties.ShowPacket()) || (ServerConstants.Use_Localhost) || (ServerProperties.IsLvkejian())) {
            if (ServerProperties.ShowPacket()) {
                int packetLen = input.length;
                int pHeader = readFirstShort(input);
                String pHeaderStr = Integer.toHexString(pHeader).toUpperCase();
                pHeaderStr = StringUtil.getLeftPaddedStr(pHeaderStr, '0', 4);
                String op = lookupRecv(pHeader);
                String Recv = "【服务端发送】 " + op + "  [0x" + pHeaderStr + "]  (" + packetLen + "字节)  " + FileoutputUtil.CurrentReadable_Time() + "\r\n";

                if (packetLen <= 60000) {
                    String RecvTo = Recv + HexTool.toString(input) + "\r\n" + HexTool.toStringFromAscii(input);
                    FileoutputUtil.packetLog("log\\PacketLog.log", RecvTo);
                    System.out.println(RecvTo + "\r\n");

                    if (!ServerProperties.SendPacket(op, pHeaderStr)) {

                        String SendTos = "\r\n时间：" + FileoutputUtil.CurrentReadable_Time() + "\r\n";
                        if ((op.equals("GIVE_BUFF")) || (op.equals("CANCEL_BUFF"))) {
                            FileoutputUtil.packetLog("log\\SkillBuffLog.log", SendTos + RecvTo);
                        } else if (op.endsWith("PLAYER_INTERACTION")) {
                            FileoutputUtil.packetLog("log\\玩家互动封包.log", SendTos + RecvTo);
                        }

                    }

                } else {
                    System.out.println(Recv + HexTool.toString(new byte[]{input[0], input[1]}) + "...\r\n");
                }
            }
            
            byte[] unencrypted = new byte[input.length];
            System.arraycopy(input, 0, unencrypted, 0, input.length);
            byte[] ret = new byte[unencrypted.length + 4];
            Lock mutex = client.getLock();
            mutex.lock();
            try {
                byte[] header = send_crypto.getPacketHeader(unencrypted.length);

                send_crypto.crypt(unencrypted);
                System.arraycopy(header, 0, ret, 0, 4);
            } finally {
                mutex.unlock();
            }
            System.arraycopy(unencrypted, 0, ret, 4, unencrypted.length);
            out.write(IoBuffer.wrap(ret));
        } else {
            out.write(IoBuffer.wrap((byte[]) (byte[]) message));
        }
    }

    @Override
    public void dispose(IoSession session) throws Exception {
    }

    private String lookupRecv(int val) {
        for (SendPacketOpcode op : SendPacketOpcode.values()) {
            if (op.getValue() == val) {
                return op.name();
            }
        }
        return "UNKNOWN";
    }

    private int readFirstShort(byte[] arr) {
        return new GenericLittleEndianAccessor(new ByteArrayByteStream(arr)).readShort();
    }
}
